// Mesh
// (c) jimon game studio

#ifndef JEH_JEMESH
#define JEH_JEMESH

#include "jeUnknown.h"
#include "jeStl.h"
#include "ISurface.h"
#include "jeSkeleton.h"

namespace je
{
	namespace scene
	{
		//! Mesh
		class jeMesh:public je::jeUnknown
		{
		public:
			//! Surfaces List Type
			typedef jeList<ISurface*> SurfacesListType;

			//! Mesh List Type
			typedef jeList<jeMesh*> MeshListType;

		protected:
			//! Surfaces List
			SurfacesListType Surfaces;

			//! Meshes List
			MeshListType Meshes;

			//! Parent
			jeMesh * Parent;

			//! Name
			jeStringw Name;

			//! Model Matrix
			jeMatrix4f ModelMatrix;

			//! Skeleton
			jeSkeleton * Skeleton;
		public:
			//! Constructor
			jeMesh()
				:Parent(NULL),Skeleton(NULL)
			{
			}

			//! Destructor
			virtual ~jeMesh()
			{
				SetSkeleton(NULL);

				for(SurfacesListType::Iterator Iter = Surfaces.begin();Iter != Surfaces.end();Iter++)
					(*Iter)->Drop();
				Surfaces.clear();

				for(MeshListType::Iterator Iter = Meshes.begin();Iter != Meshes.end();Iter++)
					(*Iter)->Drop();
				Meshes.clear();
			}

			//! Set Name
			virtual void SetName(const jeStringw & NewName)
			{
				Name = NewName;
			}

			//! Get Name
			virtual const jeStringw & GetName()
			{
				return Name;
			}

			//! Set Model Matrix
			virtual void SetModelMatrix(const jeMatrix4f & NewModelMatrix)
			{
				ModelMatrix = NewModelMatrix;
			}

			//! Get Model Matrix
			virtual const jeMatrix4f & GetModelMatrix()
			{
				return ModelMatrix;
			}

			////! Build Absolute Model Matrix
			//virtual void BuildAbsoluteModelMatrix(const jeMatrix4f & ParentMatrix)
			//{
			//	RebuildTransformations();
			//	AbsoluteModelMatrix = ParentMatrix * ModelMatrix;
			//	for(MeshListType::Iterator Iter = Meshes.begin();Iter != Meshes.end();Iter++)
			//		(*Iter)->BuildAbsoluteModelMatrix(AbsoluteModelMatrix);
			//}

			//! Get Meshes
			virtual SurfacesListType & GetSurfaces()
			{
				return Surfaces;
			}

			//! Get Surfaces
			virtual MeshListType & GetMeshes()
			{
				return Meshes;
			}

			//! Set Parent
			virtual void SetParent(jeMesh * NewParent)
			{
				Parent = NewParent;
			}

			//! Get Parent
			virtual jeMesh * GetParent()
			{
				return Parent;
			}

			//! Add Children
			virtual void AddChildren(jeMesh * Mesh)
			{
				Mesh->Grab();

				if(Mesh->GetParent())
					Mesh->GetParent()->RemoveChildren(Mesh);

				Mesh->SetParent(this);
				Meshes.push_back(Mesh);
			}

			//! Remove Children
			virtual void RemoveChildren(jeMesh * Mesh)
			{
				for(MeshListType::Iterator Iter = Meshes.begin();Iter != Meshes.end();Iter++)
					if ((*Iter) == Mesh)
					{
						Meshes.erase(Iter);
						Mesh->SetParent(NULL);
						Mesh->Drop();
						return;
					}
			}

			//! Remove Itself
			virtual void RemoveItself()
			{
				if(Parent)
					Parent->RemoveChildren(this);
				else
					this->Drop();
			}

			//! Add Surface
			virtual void AddSurface(ISurface * Surface)
			{
				Surface->Grab();
				Surfaces.push_back(Surface);
			}

			//! Remove Surface
			virtual void RemoveSurface(ISurface * Surface)
			{
				for(SurfacesListType::Iterator Iter = Surfaces.begin();Iter != Surfaces.end();Iter++)
				{
					if((*Iter) == Surface)
					{
						Surface->Drop();
						Surfaces.erase(Iter);
						return;
					}
				}
			}

			//! On Render
			virtual void OnRender(const jeMatrix4f & AbsoluteModelMatrix)
			{
				jeMatrix4f TempAbsModelMatrix = AbsoluteModelMatrix * ModelMatrix;
				for(MeshListType::Iterator Iter = Meshes.begin();Iter != Meshes.end();Iter++)
					(*Iter)->OnRender(TempAbsModelMatrix);

				for(SurfacesListType::Iterator Iter = Surfaces.begin();Iter != Surfaces.end();Iter++)
					(*Iter)->OnRender(TempAbsModelMatrix);
			}

			//! Is There All Materials Are Transparent
			virtual u1 IsThereAllMaterialsAreTransparent()
			{
				for(MeshListType::Iterator Iter = Meshes.begin();Iter != Meshes.end();Iter++)
				{
					if(!(*Iter)->IsThereAllMaterialsAreTransparent())
						return false;
				}

				for(SurfacesListType::Iterator Iter = Surfaces.begin();Iter != Surfaces.end();Iter++)
				{
					if((!(*Iter)->GetMaterial()) || ((*Iter)->GetMaterial()->Type == video::MT_SOLID))
						return false;
				}

				return true;
			}

			//! Set Skeleton
			virtual void SetSkeleton(jeSkeleton * NewSkeleton)
			{
				if(Skeleton)
					Skeleton->Drop();

				Skeleton = NewSkeleton;

				if(Skeleton)
					Skeleton->Grab();
			}

			//! Get Skeleton
			virtual jeSkeleton * GetSkeleton()
			{
				return Skeleton;
			}

			//! Get Mesh With Skeleton
			virtual jeMesh * GetMeshWithSkeleton()
			{
				if(Skeleton)
					return this;

				jeMesh * Mesh = NULL;

				for(MeshListType::Iterator Iter = Meshes.begin();Iter != Meshes.end();Iter++)
				{
					jeMesh * Temp = (*Iter)->GetMeshWithSkeleton();
					if(Temp)
					{
						Mesh = Temp;
						break;
					}
				}

				return Mesh;
			}

			//! Is There Skeleton ?
			virtual u1 IsThereSkeleton()
			{
				u1 ThereSkeleton = false;

				for(MeshListType::Iterator Iter = Meshes.begin();Iter != Meshes.end();Iter++)
					if((*Iter)->IsThereSkeleton())
					{
						ThereSkeleton = true;
						break;
					}

				if(Skeleton || ThereSkeleton)
					return true;
				else
					return false;
			}
		};
	}
}

#endif
